package com.tools.s7.recycler;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tools.s7.R;
import com.tools.s7.recycler.holder.BaseHolder;
import com.tools.s7.recycler.holder.BaseViewHolder;
import com.tools.s7.recycler.holder.ErrorViewHolder;
import com.tools.s7.recycler.holder.FooterViewHolder;
import com.tools.s7.recycler.holder.LoadErrorHolder;
import com.tools.s7.recycler.holder.LoadViewHolder;
import com.tools.s7.recycler.holder.NullViewHolder;
import com.tools.s7.recycler.listener.Recycler;
import com.tools.s7.recycler.utils.BaseRecyclerCode;

import java.util.ArrayList;
import java.util.List;


public abstract class BaseRecyclerLoadAdapter<T> extends RecyclerView.Adapter<BaseHolder> {

    @Override
    public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == BaseRecyclerCode.TYPE_ITEM) {
            View view = getView(parent, getLayoutId());
            return new BaseViewHolder(view);
        } else if (viewType == BaseRecyclerCode.TYPE_LOAD) {
            View view = getView(parent, getLoadId());
            return new LoadViewHolder(view);
        } else {
            View view = getView(parent, getLoadErrorId());
            return new LoadErrorHolder(view);
        }
    }

    private View getView(ViewGroup parent, int id) {
        return LayoutInflater.from(parent.getContext()).inflate(id, parent, false);
    }

    @Override
    public void onBindViewHolder(BaseHolder holder, int position) {

        holder.setRealPosition(position);

        initListener(holder);

        if (holder instanceof BaseViewHolder) {
            initClickListener((BaseViewHolder) holder, datas.get(position));
            ((BaseViewHolder) holder).setData(datas.get(position));
            bindData((BaseViewHolder) holder, position, datas.get(position));
        }

        if (holder instanceof LoadViewHolder) {
            bindLoad((LoadViewHolder) holder, position);
        }

        if (holder instanceof LoadErrorHolder) {
            bindLoadError((LoadErrorHolder) holder, position);
        }
    }

    @Override
    public int getItemCount() {
        if (isLegal() && !isFirst) {
            return datas == null ? 1 : datas.size() + 1;
        }
        return datas == null ? 0 : datas.size();
    }

    public boolean isLegal() {
        return (isLoad || isLoadError);
    }

    @Override
    public int getItemViewType(int position) {



        if (isLoad && position + 1 == getItemCount()) {
            return BaseRecyclerCode.TYPE_LOAD;
        }

        if (isLoadError && position + 1 == getItemCount()) {
            return BaseRecyclerCode.TYPE_LOAD_ERROR;
        }

        return BaseRecyclerCode.TYPE_ITEM;
    }

    protected abstract int getLayoutId();

    protected int getLoadId() {
        return R.layout.tools_load;
    }

    protected int getLoadErrorId() {
        return R.layout.tools_load_error;
    }

    protected abstract void bindData(BaseViewHolder holder, int position, T data);

    protected void bindLoadError(LoadErrorHolder holder, int position) {

    }

    protected void bindLoad(LoadViewHolder holder, int position) {

    }

    protected List<T> datas;
    private boolean isFirst = true;
    private boolean isAadditional = true;
    private boolean isLoad = true;
    private boolean isLoadError = false;
    protected Recycler.OnLoadingListener loadingListener;


    public BaseRecyclerLoadAdapter setAadditional(boolean aadditional) {
        isAadditional = aadditional;
        return this;
    }

    public BaseRecyclerLoadAdapter setLoad(boolean load) {
        if (isAadditional) {
            isLoad = load;
        } else {
            isLoad = false;
        }
        return this;
    }


    public BaseRecyclerLoadAdapter setLoadError(boolean loadError) {
        if (isAadditional) {
            isLoadError = loadError;
            isLoad = !isLoadError;
        } else {
            isLoadError = false;
            isLoad = false;
        }
        notifyDataSetChanged();
        return this;
    }

    public BaseRecyclerLoadAdapter setLoadingListener(Recycler.OnLoadingListener loadingListener) {
        this.loadingListener = loadingListener;
        return this;
    }

    protected Recycler.OnCheckedChangeListener mCheckedChange;
    protected Recycler.OnClickListener<T> mClick;
    protected Recycler.OnItemClickListener<T> mItemClick;
    protected Recycler.OnItemLongClickListener<T> mItemLongClick;


    protected void initClickListener(final BaseViewHolder holder, final T data) {
        if (mItemClick != null)
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mItemClick.onItemClick(holder.getRealPosition(), data);
                }
            });

        if (mItemLongClick != null) {
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    mItemLongClick.onItemLongClick(holder.getRealPosition(), data);
                    return false;
                }
            });
        }
    }


    protected void initListener(final BaseHolder holder) {


        if (holder instanceof LoadErrorHolder) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    setLoadError(false);
                }
            });
        }

        if (holder instanceof LoadViewHolder) {
            if (loadingListener != null) {
                loadingListener.onLoading();
            }
        }

        if (holder instanceof ErrorViewHolder) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (loadingListener != null) {
                        loadingListener.onReload();
                    }
                }
            });
        }

    }

    public BaseRecyclerLoadAdapter setCheckedChange(Recycler.OnCheckedChangeListener<T> mCheckedChange) {
        this.mCheckedChange = mCheckedChange;
        return this;
    }

    public BaseRecyclerLoadAdapter setClick(Recycler.OnClickListener<T> mClick) {
        this.mClick = mClick;
        return this;
    }

    public BaseRecyclerLoadAdapter setItemClick(Recycler.OnItemClickListener<T> mItemClick) {
        this.mItemClick = mItemClick;
        return this;
    }

    public BaseRecyclerLoadAdapter setItemLongClick(Recycler.OnItemLongClickListener<T> mItemLongClick) {
        this.mItemLongClick = mItemLongClick;
        return this;
    }

    public BaseRecyclerLoadAdapter() {
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
    }

    public BaseRecyclerLoadAdapter(List<T> datas) {
        this.datas = datas;
    }

    public void onRefresh(List<T> datas) {
        initFlag();
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
        this.datas.clear();
        if (datas != null) {
            this.datas.addAll(datas);
        }
        notifyDataSetChanged();
    }

    private void initFlag() {
        isFirst = false;
        if (isAadditional) {
            isLoadError = false;
            isLoad = true;
        } else {
            isLoadError = false;
            isLoad = false;
        }

    }

    public void addDatas(List<T> datas) {
        if (datas != null) {
            this.datas.addAll(datas);
            notifyDataSetChanged();
        }
    }

    public void addData(T data) {
        if (data != null) {
            this.datas.add(data);
            notifyDataSetChanged();
        }
    }

    public void onReplace(int position, T data) {
        if (position < this.datas.size() && data != null) {
            this.datas.set(position, data);
            notifyDataSetChanged();
        }
    }

    public void onRemove(int position) {
        if (position < this.datas.size()) {
            this.datas.remove(position);
            notifyDataSetChanged();
        }
    }

    public List<T> getDatas() {
        return datas;
    }
}
